package com.dog.modules.websocket.handler;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import com.dog.framework.core.constant.CleaningRedisKeyPrefixConst;
import com.dog.modules.websocket.config.WsSessionManager;
import com.dog.modules.websocket.domain.WsMsgType;
import com.dog.modules.websocket.domain.WsPayload;
import com.dog.modules.websocket.domain.enums.ClientTypeEnum;
import com.dog.modules.websocket.domain.req.DeviceRequestData;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;



/**
 * App websocket Handler
 */
@Component
@Slf4j
public class AppSSHSocketHandler extends TextWebSocketHandler {

    @Autowired
    private WsSessionManager wsSessionManager;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    ThreadPoolExecutor executor = new ThreadPoolExecutor(
            10,
            100,
            1,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1000), new DefaultThreadFactory("AppSshSocketThread"));

    /**
     * socket 建立成功事件
     *
     * @param webSocketSession
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) {
//        Long userId = (Long) webSocketSession.getAttributes().get(PARAM_KEY_USER_ID);
//        String key = String.format(WS_USERID_SESSION, userId);
        // 用户连接成功，放入在线用户缓存
        wsSessionManager.add(ClientTypeEnum.APP.getCode(), webSocketSession.getId(), webSocketSession);
    }

    /**
     * 接收消息事件
     *
     * @param webSocketSession
     * @param webSocketMessage
     * @throws Exception
     */
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage webSocketMessage) throws Exception {
        // 消息内容
        String reqPayloadStr = webSocketMessage.getPayload().toString();
        WsPayload reqPayload = JSON.parseObject(reqPayloadStr, WsPayload.class);
        // 检查session
        log.info("receive msg: {} from app client {}", reqPayloadStr, webSocketSession.getId());
        executor.execute(() -> {
            WsPayload respPayload = null;
            switch (WsMsgType.valueOf(reqPayload.getType())) {
                case HEARTBEAT:
                    respPayload = handleHeartBeat(reqPayloadStr);
                    break;
                default:
                    break;
            }
            wsSessionManager.sendMessage(webSocketSession, respPayload);
        });
    }

    private WsPayload handleHeartBeat(String reqPayloadStr) {
        WsPayload<DeviceRequestData> reqPayload = JSON.parseObject(reqPayloadStr, new TypeReference<WsPayload<DeviceRequestData>>() {
        }.getType());
        WsPayload respPayload = new WsPayload();
        respPayload.setType(WsMsgType.HEARTBEAT.getCmd());
        respPayload.setTimestamp(System.currentTimeMillis());
        String realtimeDta = this.redisTemplate.opsForValue().get(String.format(CleaningRedisKeyPrefixConst.ROBOT_REALTIME_DATA, reqPayload.getData().getDeviceId()));
        respPayload.setData(JSON.parseObject(realtimeDta, JsonObject.class));
        return respPayload;
    }

    /**
     * socket 断开连接时
     *
     * @param webSocketSession
     * @param closeStatus
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) {
        // 用户退出，移除缓存
        wsSessionManager.removeAndClose(ClientTypeEnum.APP.getCode(), webSocketSession.getId());
    }
}
